#ifndef __UTIL_HPP__
#define __UTIL_HPP__
#include <iostream>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <unordered_map>
#include <fstream>
#include "error.hpp"
#define INFO 0
#define DEBUG 1
#define ERROR 2
#define LOG(level, format, ...)                                                                                    \
    do                                                                                                             \
    {                                                                                                              \
        std::string levelStr;                                                                                      \
        if (level == INFO)                                                                                         \
            levelStr = "INFO";                                                                                     \
        else if (level == DEBUG)                                                                                   \
            levelStr = "DEBUG";                                                                                    \
        else                                                                                                       \
            levelStr = "ERROR";                                                                                    \
                                                                                                                   \
        time_t t = time(nullptr);                                                                                  \
        struct tm *lt = localtime(&t);                                                                             \
        char buffer[32];                                                                                           \
        strftime(buffer, 32, "%H:%M:%S", lt);                                                                      \
        fprintf(stdout, "[%s:%s %s:%d]" format "\n", levelStr.c_str(), buffer, __FILE__, __LINE__, ##__VA_ARGS__); \
    } while (0)
#define ILOG(format, ...) LOG(INFO, format, ##__VA_ARGS__)
#define DLOG(format, ...) LOG(DEBUG, format, ##__VA_ARGS__)
#define ELOG(format, ...) LOG(ERROR, format, ##__VA_ARGS__)

class Util
{
public:
    static int readline(int sockfd, std::string &out)
    {
        char ch;
        int num = 0;
        do
        {
            ssize_t n = recv(sockfd, &ch, 1, 0);
            if (n > 0)
            {
                if (ch == '\r')
                {
                    // 数据窥探查看缓冲区中下一个字符是什么
                    recv(sockfd, &ch, 1, MSG_PEEK);
                    if (ch == '\n')
                    {
                        // 窥探成功
                        recv(sockfd, &ch, 1, 0);
                    }
                    ch = '\n';
                }
                out += ch;
                ++num;
            }
            else if (n == 0)
            {
                DLOG("client close connect , sockfd:%d", sockfd);
                return 0;
            }
            else
            {
                ELOG("server recv error!");
                return RECV_ERROR;
            }
        } while (ch != '\n');
        return num;
    }
    static bool splitstring(const std::string &str, std::string &sub1_out, std::string &sub2_out, const std::string &sep)
    {
        size_t pos = str.find(sep);
        if (pos != std::string::npos)
        {
            sub1_out = str.substr(0, pos);
            sub2_out = str.substr(pos + sep.size(), std::string::npos);
            return true;
        }
        else
        {
            return false;
        }
    }
    static std::string CodeToDesc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "file Not Found";
        case 405:
            return "Method Not Allowed";
        default:
            return "Unkown";
        }
    }
    static std::string SuffixToType(const std::string &filename)
    {
        static std::unordered_map<std::string, std::string> suffixtotype{
            {"html", "text/html"},
            {"css", "text/css"},
            {"eot", "application/vnd.ms-fontobject"},
            {"ttf", "font/ttf"},
            {"woff", "font/woff"},
            {"woff2", "font/woff2"},
            {"jpg", "image/jpeg"},
            {"jpeg", "image/jpeg"},
            {"js", "application/x-javascript"},
            {"svg", "image/svg+xml"},
            {"ico", "image/x-icon"},
            {"gif", "image/gif"},
            {"png", "image/png"},
        }; 
        size_t found = filename.rfind('.');
        if(found != std::string::npos)
        {
            auto iter = suffixtotype.find(filename.substr(found+1));
            if(iter == suffixtotype.end()) return "text/html";
            else return iter->second;
        }
        return "";
    }
};

#endif
